home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / utility / uwserver.zip / uwserver.tar / server / uw_opt.c < prev    next >
C/C++ Source or Header  |  1991-01-25  |  14KB  |  611 lines

  1. /*
  2.  *    uw_opt - window option handling for UW
  3.  *
  4.  * Copyright 1986 by John D. Bruner.  All rights reserved.  Permission to
  5.  * copy this program is given provided that the copy is not sold and that
  6.  * this copyright notice is included.
  7.  */
  8.  
  9. #include <sys/types.h>
  10.  
  11. #include "uw_param.h"
  12. #include "uw_opt.h"
  13.  
  14. /*
  15.  * The following variable is a kludge for efficiency.  It is set to
  16.  * a nonzero value when a bitmask is changed, indicating that opt_scan()
  17.  * should be called.
  18.  */
  19. int calloptscan;            /* pending,do,dont awaits opt_scan */
  20.  
  21. /* option input state variables */
  22. static caddr_t optwin;            /* window */
  23. static struct woptdefn *optwod;        /* window option definition */
  24. static woptcmd_t optcmd;        /* option command */
  25. static woption_t optnum;        /* current option number */
  26. static woptarg_t *optarg;        /* current encoding */
  27. static int optcnt;            /* count in current encoding */
  28. static char *optout;            /* decoded option */
  29. static char optbuf[512];        /* buffer for decoded option */
  30.  
  31. opt_new(wod, generic, unique)
  32. register struct woptdefn *wod, *generic, *unique;
  33. {
  34.     register int n, mask;
  35.  
  36.     /*
  37.      * Set up the option definition structure pointed to by "wod" to
  38.      * correspond with the option definitions in "generic" (common to
  39.      * all window types) and "unique" (per-window).
  40.      */
  41.     mask = (1<<(WONUM_GENERIC+1))-1;
  42.     if (unique) {
  43.         wod->wod_askrpt = unique->wod_askrpt & ~mask;
  44.         wod->wod_pending = unique->wod_pending & ~mask;
  45.         for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
  46.             wod->wod_optlst[n] = unique->wod_optlst[n];
  47.     } else {
  48.         wod->wod_askrpt = 0;
  49.         wod->wod_pending = 0;
  50.         for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
  51.             wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
  52.     }
  53.     if (generic) {
  54.         wod->wod_askrpt |= generic->wod_askrpt & mask;
  55.         wod->wod_pending |= generic->wod_pending & mask;
  56.         for (n=1; n <= WONUM_GENERIC; n++)
  57.             wod->wod_optlst[n] = generic->wod_optlst[n];
  58.     } else {
  59.         for (n=1; n <= WONUM_GENERIC; n++)
  60.             wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
  61.     }
  62.     wod->wod_do = wod->wod_askrpt;
  63.     wod->wod_dont = 0;
  64.     wod->wod_inquire = 0;
  65.     calloptscan = 1;
  66. }
  67.  
  68. opt_renew(wod, report)
  69. register struct woptdefn *wod;
  70. int report;
  71. {
  72.     /*
  73.      * Reset "wod_do" for all window options that we want the Macintosh
  74.      * to report to us.  If "report" is nonzero, send the Mac the
  75.      * current values of these options.
  76.      */
  77.     wod->wod_do = wod->wod_askrpt;
  78.     wod->wod_dont = 0;
  79.     if (report)
  80.         wod->wod_pending = wod->wod_askrpt;
  81.     calloptscan = 1;
  82. }
  83.  
  84. opt_newtype(wod, generic, unique)
  85. register struct woptdefn *wod, *generic, *unique;
  86. {
  87.     register int n, bit;
  88.     register woptbmask_t oldask;
  89.  
  90.     /*
  91.      * Change the window options to reflect a new window emulation type.
  92.      * The new emulation may not support all of the events that the old
  93.      * one did, and in any event they may not mean the same thing.
  94.      */
  95.     oldask = wod->wod_askrpt;
  96.     opt_new(wod, generic, unique);
  97.     for (n=1, bit=2; n <= WONUM_GENERIC; n++,bit<<=1) {
  98.         if ((oldask&bit) && !(wod->wod_askrpt&bit))
  99.             wod->wod_dont |= bit;
  100.         if (!(oldask&bit) && (wod->wod_askrpt&bit))
  101.             wod->wod_do |= bit;
  102.     }
  103.     for ( ; n <= WONUM_MAX; n++, bit<<=1)
  104.         if (wod->wod_askrpt&bit)
  105.             wod->wod_do |= bit;
  106.     calloptscan = 1;
  107. }
  108.  
  109. opt_setext(wod, fn)
  110. register struct woptdefn *wod;
  111. register void (*fn)();
  112. {
  113.     register int n;
  114.  
  115.     /*
  116.      * Set "wol_ext" to "fn" for each option that has a defined "wol_set".
  117.      */
  118.     for (n=1; n <= WONUM_MAX; n++)
  119.         if (wod->wod_optlst[n].wol_set)
  120.             wod->wod_optlst[n].wol_ext = fn;
  121. }
  122.  
  123. opt_scan(w, wod, fn, mfd, cmd)
  124. caddr_t w;
  125. register struct woptdefn *wod;
  126. void (*fn)();
  127. fildes_t mfd;
  128. int cmd;
  129. {
  130.     register struct woptlst *wol;
  131.     register char *cp;
  132.     register int n, bit, maxsize;
  133.     char buf[512];
  134.  
  135.     /*
  136.      * Scan the entire list of options for pending ones.  For each
  137.      * one, call "fn".  "cmd" is the command that we are to pass as the
  138.      * first argument to "fn".
  139.      *
  140.      * Note that we must send data (wod_pending) before processing
  141.      * DO commands (wod_do); otherwise, the host and Mac may not
  142.      * agree upon the value of a window option.  (The Mac might
  143.      * respond to the "do" command before it sees the new value.)
  144.      */
  145.     cp = buf;
  146. #ifdef notdef
  147.     for (n=1,bit=2,wol=wod->wod_optlst+1; n<=WONUM_MAX; n++,bit<<=1,wol++) {
  148. #else
  149.     for (n=WONUM_MAX, bit=(1<<WONUM_MAX), wol=wod->wod_optlst+WONUM_MAX;
  150.          n > 0;
  151.          n--, bit >>= 1, wol--) {
  152. #endif
  153.         if (wod->wod_pending&bit) {
  154.             wod->wod_pending &= ~bit;
  155.             if (wol->wol_argdefn) {
  156.                 maxsize = 2 +
  157.                     opt_size(wol->wol_argdefn);
  158.                 if (cp > buf + sizeof buf - maxsize - 1) {
  159.                     *cp++ = 0;
  160.                     (*fn)(mfd, cmd, buf, cp-buf);
  161.                     cp = buf;
  162.                 }
  163.                 if (WONUM_USELONG(n)) {
  164.                     *cp++ = WOC_SET|WONUM_LPREFIX;
  165.                     *cp++ = WONUM_LENCODE(n);
  166.                 } else
  167.                     *cp++ = WOC_SET|WONUM_SENCODE(n);
  168.                 cp += opt_encode(cp, wol->wol_argdefn,
  169.                     (*wol->wol_get)(w, n));
  170.             }
  171.         }
  172.         if (wod->wod_inquire&bit) {
  173.             wod->wod_inquire &= ~bit;
  174.             if (cp > buf + sizeof buf - 3) {
  175.                 *cp++ = 0;
  176.                 (*fn)(mfd, cmd, buf, cp-buf);
  177.                 cp = buf;
  178.             }
  179.             if (wol->wol_argdefn) {
  180.                 if (WONUM_USELONG(n)) {
  181.                     *cp++ = WOC_INQUIRE|WONUM_LPREFIX;
  182.                     *cp++ = WONUM_LENCODE(n);
  183.                 } else
  184.                     *cp++ = WOC_INQUIRE|WONUM_SENCODE(n);
  185.             }
  186.         }
  187.         if ((wod->wod_do|wod->wod_dont)&bit) {
  188.             if (cp > buf + sizeof buf - 3) {
  189.                 *cp++ = 0;
  190.                 (*fn)(mfd, cmd, buf, cp-buf);
  191.                 cp = buf;
  192.             }
  193.             if (wod->wod_do&bit) {
  194.                 wod->wod_do &= ~bit;
  195.                 wod->wod_dont &= ~bit;
  196.                 if (wol->wol_argdefn) {
  197.                     if (WONUM_USELONG(n)) {
  198.                         *cp++ = WOC_DO|WONUM_LPREFIX;
  199.                         *cp++ = WONUM_LENCODE(n);
  200.                     } else
  201.                         *cp++ = WOC_DO|WONUM_SENCODE(n);
  202.                 }
  203.             } else if (wod->wod_dont&bit) {
  204.                 wod->wod_do &= ~bit;
  205.                 wod->wod_dont &= ~bit;
  206.                 if (wol->wol_argdefn) {
  207.                     if (WONUM_USELONG(n)) {
  208.                         *cp++ = WOC_DONT|WONUM_LPREFIX;
  209.                         *cp++ = WONUM_LENCODE(n);
  210.                     } else
  211.                         *cp++=WOC_DONT|WONUM_SENCODE(n);
  212.                 }
  213.             }
  214.         }
  215.         if (cp > buf) {
  216.             *cp++ = 0;
  217.             (*fn)(mfd, cmd, buf, cp-buf);
  218.             cp = buf;
  219.         }
  220.     }
  221. }
  222.  
  223. opt_size(woa)
  224. register woptarg_t *woa;
  225. {
  226.     register int size, cnt;
  227.  
  228.     /*
  229.      * Determine the maximum size of an option whose argument encoding
  230.      * is specified by "woa".  This does NOT include additional encoding
  231.      * (e.g. for meta characters) at the protocol level.
  232.      */
  233.     if (woa) {
  234.         for (size=0; *woa != WOA_END; woa++) {
  235.             cnt = *woa & ~WOA_CMDMASK;
  236.             switch (*woa & WOA_CMDMASK) {
  237.             case WOA_CHARS(0):
  238.             case WOA_STRING(0):
  239.                 size += cnt;
  240.                 break;
  241.             case WOA_UDATA(0):
  242.                 size += (cnt + 5) / 6;
  243.                 break;
  244.             }
  245.         }
  246.     } else
  247.         size = 0;
  248.     return(size);
  249. }
  250.  
  251. opt_encode(buf, woa, data)
  252. char *buf;
  253. register woptarg_t *woa;
  254. char *data;
  255. {
  256.     register char *cp, *cq;
  257.     register int n, cnt;
  258.     register unsigned long ival;
  259.     union {
  260.         struct {
  261.             char    c1;
  262.             short    s;
  263.         }    cs;
  264.         struct {
  265.             char    c2;
  266.             long    l;
  267.         }    cl;
  268.     } u;
  269.  
  270.     /*
  271.      * Encode "data" according to the option argument specifier "woa"
  272.      * into the buffer "buf".  Return the number of bytes of "buf"
  273.      * actually used.  The caller has already verified that "buf" is
  274.      * large enough.
  275.      */
  276.     if (!data)
  277.         return(0);
  278.     for (cp=buf,cq=data; *woa != WOA_END; woa++) {
  279.         cnt = *woa & ~WOA_CMDMASK;
  280.         switch (*woa & WOA_CMDMASK) {
  281.         case WOA_CHARS(0):
  282.             for (n=0; n < cnt; n++)
  283.                 *cp++ = *cq++;
  284.             break;
  285.         case WOA_STRING(0):
  286.             for (n=0; n < cnt-1 && *cq; n++)
  287.                 *cp++ = *cq++;
  288.             if (n < cnt)
  289.                 cq += cnt-n;
  290.             *cp++ = '\0';
  291.             break;
  292.         case WOA_UDATA(0):
  293.             if (cnt <= NBBY) {
  294.                 ival = (unsigned char)*cq++;
  295.             } else if (cnt <= sizeof(short)*NBBY) {
  296.                 while ((int)cq & ((char *)&u.cs.s-&u.cs.c1-1))
  297.                     cq++;
  298.                 ival = *(unsigned short *)cq;
  299.                 cq += sizeof(short);
  300.             } else {
  301.                 while ((int)cq & ((char *)&u.cl.l-&u.cl.c2-1))
  302.                     cq++;
  303.                 ival = *(unsigned long *)cq;
  304.                 cq += sizeof(long);
  305.             }
  306.             if (cnt != sizeof(long)*NBBY)
  307.                 ival &= (1<<cnt) - 1;
  308.             for (n=0; n < cnt; n += 6, ival >>= 6)
  309.                 *cp++ = (ival & 077) | 0100;
  310.             break;
  311.         }
  312.     }
  313.     return(cp-buf);
  314. }
  315.             
  316. opt_istart(w, wod)
  317. caddr_t w;
  318. struct woptdefn *wod;
  319. {
  320.     /*
  321.      * Start collecting input for a window option specification.
  322.      */
  323.     optwin = w;
  324.     optwod = wod;
  325.     optnum = 0;
  326. }
  327.  
  328. opt_input(c)
  329. char c;
  330. {
  331.     register int cnt, bit;
  332.     register struct woptdefn *wod;
  333.     register struct woptlst *wol;
  334.     register unsigned long ival;
  335.     union {
  336.         struct {
  337.             char    c1;
  338.             short    s;
  339.         }    cs;
  340.         struct {
  341.             char    c2;
  342.             long    l;
  343.         }    cl;
  344.     } u;
  345.  
  346.     /*
  347.      * Add the received character "c" to the current option specification.
  348.      * If it is complete, take the appropriate action.  If option 0
  349.      * (the endmarker) is received, return 0 (to notify the caller that
  350.      * we are done).  Otherwise, return 1 -- more option data remains
  351.      * to be processed.
  352.      *
  353.      * This code isn't as readable as it should be; there are far too
  354.      * many return statements floating around.  Sorry about that.
  355.      */
  356.     if (optwin) {
  357.         wod = optwod;
  358.         if (optnum == 0 || optnum == WONUM_MAX+1) {
  359.             /* start (or continue) decoding a new option */
  360.             if (optnum == 0) {
  361.                 /* start new option (or decode endmarker) */
  362.                 if (c & WONUM_MASK) {
  363.                     /* new option */
  364.                     optcmd = c & WOC_MASK;
  365.                     if (WOC_BADCMD(optcmd)) {
  366.                         opt_iflush();
  367.                         return(0);
  368.                     }
  369.                     if (c == WONUM_LPREFIX) {
  370.                         optnum = WONUM_MAX+1;
  371.                         return(1);
  372.                     } else
  373.                         optnum = WONUM_SDECODE(c);
  374.                 } else {
  375.                     /* end of options */
  376.                     opt_iflush();
  377.                     return(0);
  378.                 }
  379.             } else {
  380.                 /* read second byte of long option number */
  381.                 optnum = WONUM_LDECODE(c);
  382.                 if (optnum > WONUM_MAX) {
  383.                     opt_iflush();
  384.                     return(0);
  385.                 }
  386.             }
  387.             /*
  388.              * This point is reached when the option number has
  389.              * been completely decoded.  If the command is not
  390.              * WOC_SET, then it has no arguments and we can
  391.              * process it immediately.
  392.              */
  393.             wol = &wod->wod_optlst[optnum];
  394.             bit = 1<<optnum;
  395.             if (optcmd == WOC_SET) {
  396.                 optout = optbuf;
  397.                 optcnt = 0;
  398.                 optarg = wol->wol_argdefn;
  399.                 if (!optarg) {
  400.                     opt_iflush();
  401.                     return(0);
  402.                 }
  403.             } else {
  404.                 if (wol->wol_ext &&
  405.                     (optcmd == WOC_WILL || optcmd == WOC_WONT))
  406.                     (*wol->wol_ext)(optwin, optcmd,
  407.                         optnum, (char *)0, 0);
  408.                 switch (optcmd) {
  409.                 case WOC_INQUIRE:
  410.                     wod->wod_pending |= bit;
  411.                     calloptscan = 1;
  412.                     break;
  413.                 case WOC_DO:
  414.                 case WOC_DONT:
  415.                     break;
  416.                 case WOC_WILL:
  417.                     wod->wod_askrpt |= bit;
  418.                     wod->wod_do &= ~bit;
  419.                     break;
  420.                 case WOC_WONT:
  421.                     wod->wod_askrpt &= ~bit;
  422.                     wod->wod_dont &= ~bit;
  423.                     break;
  424.                 }
  425.                 optnum = 0;
  426.             }
  427.             return(1);
  428.         } else {
  429.             /* continue processing argument to option */
  430.             wol = &wod->wod_optlst[optnum];
  431.             bit = 1<<optnum;
  432.             cnt = *optarg & ~WOA_CMDMASK;
  433.             switch (*optarg & WOA_CMDMASK) {
  434.             case WOA_CHARS(0):
  435.                 *optout++ = c;
  436.                 optcnt++;
  437.                 break;
  438.             case WOA_STRING(0):
  439.                 *optout++ = c;
  440.                 optcnt++;
  441.                 if (!c) {
  442.                     optout += cnt - optcnt;
  443.                     optcnt = cnt;
  444.                 } else if (optcnt == cnt-1) {
  445.                     *optout++ = '\0';
  446.                     optcnt = cnt;
  447.                 }
  448.                 break;
  449.             case WOA_UDATA(0):
  450.                 if (optcnt == 0) {
  451.                     if (cnt <= NBBY) {
  452.                         *optout = 0;
  453.                     } else if (cnt <= sizeof(short)*NBBY) {
  454.                         while ((int)optout & ((char *)&u.cs.s-&u.cs.c1-1))
  455.                             optout++;
  456.                         *(short *)optout = 0;
  457.                     } else {
  458.                         while ((int)optout & ((char *)&u.cl.l-&u.cl.c2-1))
  459.                             optout++;
  460.                         *(long *)optout = 0;
  461.                     }
  462.                 }
  463.                 ival = (c & 077) << optcnt;
  464.                 if (cnt != NBBY*sizeof(long))
  465.                     ival &= (1<<cnt) - 1;
  466.                 optcnt += 6;
  467.                 if (cnt <= NBBY) {
  468.                     *(unsigned char *)optout |= (unsigned char)ival;
  469.                     if (optcnt >= cnt)
  470.                         optout++;
  471.                 } else if (cnt <= sizeof(short)*NBBY) {
  472.                     *(unsigned short *)optout |= (unsigned short)ival;
  473.                     if (optcnt >= cnt)
  474.                         optout += sizeof(short);
  475.                 } else {
  476.                     *(unsigned long *)optout |= ival;
  477.                     if (optcnt >= cnt)
  478.                         optout += sizeof(long);
  479.                 }
  480.                 break;
  481.             }
  482.             if (optcnt >= cnt) {
  483.                 optcnt = 0;
  484.                 if (*++optarg == WOA_END) {
  485.                     wod->wod_pending &= ~bit;
  486.                     (*wol->wol_set)(optwin, optnum, optbuf);
  487.                     if (wol->wol_ext) {
  488.                         (*wol->wol_ext)(optwin, WOC_SET,
  489.                             optnum, optbuf,
  490.                             optout-optbuf);
  491.                     }
  492.                     optnum = 0;
  493.                 }
  494.             }
  495.             return(1);
  496.         }
  497.         /*NOTREACHED*/
  498.     }
  499.     return(0);
  500. }
  501.  
  502. opt_iflush()
  503. {
  504.     optwin = (caddr_t)0;
  505. }
  506.  
  507. opt_extopt(w, wod, cmd, num, data, na)
  508. caddr_t w;
  509. register struct woptdefn *wod;
  510. woptcmd_t cmd;
  511. woption_t num;
  512. char *data;
  513. struct netadj *na;
  514. {
  515.     register struct woptlst *wol;
  516.  
  517.     if (w != NULL && wod != NULL && num <= WONUM_MAX) {
  518.         wol = wod->wod_optlst + num;
  519.         if (wol->wol_argdefn) {
  520.             switch (cmd) {
  521.             case WOC_SET:
  522.                 if (data && wol->wol_set) {
  523.                     if (na) {
  524.                         opt_netadj(wol->wol_argdefn,
  525.                             data, na);
  526.                     }
  527.                     /*
  528.                      * Set the new value and notify the Mac.
  529.                      * Because of a race condition (the Mac
  530.                      * might concurrently be sending us its
  531.                      * value for this option), we ask the
  532.                      * Mac to send back the value after it
  533.                      * is set.
  534.                      */
  535.                     (*wol->wol_set)(w, num, data);
  536.                     WOPT_SET(wod->wod_pending, num);
  537.                     WOPT_SET(wod->wod_inquire, num);
  538.                     calloptscan = 1;
  539.                 }
  540.                 break;
  541.             case WOC_INQUIRE:
  542.                 WOPT_SET(wod->wod_inquire, num);
  543.                 calloptscan = 1;
  544.                 break;
  545.             case WOC_DO:
  546.                 WOPT_SET(wod->wod_do, num);
  547.                 WOPT_SET(wod->wod_askrpt, num);
  548.                 calloptscan = 1;
  549.                 break;
  550.             case WOC_DONT:
  551.                 WOPT_SET(wod->wod_dont, num);
  552.                 WOPT_CLR(wod->wod_askrpt, num);
  553.                 calloptscan = 1;
  554.                 break;
  555.             }
  556.         }
  557.     }
  558. }
  559.  
  560. opt_netadj(woa, data, na)
  561. register woptarg_t *woa;
  562. char *data;
  563. register struct netadj *na;
  564. {
  565.     register char *cp;
  566.     register int cnt;
  567.     union {
  568.         struct {
  569.             char    c1;
  570.             short    s;
  571.         }    cs;
  572.         struct {
  573.             char    c2;
  574.             long    l;
  575.         }    cl;
  576.     } u;
  577.  
  578.     /*
  579.      * Convert an option (in internal format) from host byte order
  580.      * to network byte order.  If the two are the same then this is
  581.      * a NOP.
  582.      */
  583.     if (data && na) {
  584.         for (cp=data; *woa != WOA_END; woa++) {
  585.             cnt = *woa & ~WOA_CMDMASK;
  586.             switch (*woa & WOA_CMDMASK) {
  587.             case WOA_CHARS(0):
  588.             case WOA_STRING(0):
  589.                 cp += cnt;
  590.                 break;
  591.             case WOA_UDATA(0):
  592.                 if (cnt <= NBBY) {
  593.                     cp++;
  594.                 } else if (cnt <= sizeof(short)*NBBY) {
  595.                     while ((int)cp & ((char *)&u.cs.s-&u.cs.c1-1))
  596.                         cp++;
  597.                     *(u_short *)cp =
  598.                         (*na->na_ushort)(*(u_short *)cp);
  599.                     cp += sizeof(short);
  600.                 } else {
  601.                     while ((int)cp & ((char *)&u.cl.l-&u.cl.c2-1))
  602.                         cp++;
  603.                     *(u_short *)cp =
  604.                         (*na->na_ushort)(*(u_short *)cp);
  605.                     cp += sizeof(long);
  606.                 }
  607.             }
  608.         }
  609.     }
  610. }
  611.